package utils; 

import java.sql.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import ludi.Atleta;
import ludi.Curso;
import ludi.Modalidade;
import ludi.Usuario;
import ludi.Time;
import ludiExcecoes.AtletaExcecao;
import ludiExcecoes.ModalidadeExcecao;
import ludiExcecoes.UsuarioExcecao;

public class BancoDeDados extends Thread{

	private Connection conexao;
	private String bdTipo;
	private int porta;
	private String host;
	private String banco;
	private String usuario;
	private String senha;
	
	public BancoDeDados(String host, int porta, String usuario, String senha, String banco, String bdTipo) throws ClassNotFoundException, SQLException{
		this.banco = banco;
		this.bdTipo = bdTipo;
		this.porta = porta;
		this.host = host;
		this.usuario = usuario;
		this.senha = senha;
		
		this.conectar();
		
	}
	
        @Override
        public void run(){
            while (true){
                try {
                    sleep(1000);
                    getListaDeCursos();
                } catch (InterruptedException ex) {
                    Logger.getLogger(BancoDeDados.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SQLException ex) {
                    try {
                        this.conectar();
                    } catch (ClassNotFoundException ex1) {
                        Logger.getLogger(BancoDeDados.class.getName()).log(Level.SEVERE, null, ex1);
                    } catch (SQLException ex1) {
                        Logger.getLogger(BancoDeDados.class.getName()).log(Level.SEVERE, null, ex1);
                    }
                    Logger.getLogger(BancoDeDados.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

	public void conectar() throws ClassNotFoundException, SQLException{
		if (this.bdTipo.equals("mysql")){
			Class.forName("com.mysql.jdbc.Driver");
			this.conexao = DriverManager.getConnection("jdbc:mysql://" + this.host +":" + this.porta + "/" + this.banco, this.usuario, this.senha);
		}
	}
	
	private int execute(String sql) throws SQLException{
		int retorno = 0;
		Statement statement = conexao.createStatement();
		statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
		
		ResultSet resultado = statement.getGeneratedKeys();
		if (resultado.next()){
			retorno = resultado.getInt(1);
		}

		return retorno;	
	}

	private ArrayList<Integer> fromString(String string) {
		ArrayList<Integer> result = new ArrayList<Integer>(0);
		
		if (!(string.equals("[]"))){
		
			String[] strings = string.replace("[", "").replace("]", "").split(", ");
        	for (int i = 0; i < strings.length; i++) {
        		result.add(Integer.parseInt(strings[i]));
        	}
		}
		
        return result;
	}
	
	public void setUsuario(Usuario user) throws SQLException{
		this.execute("UPDATE Usuario SET" +
				" senha=\"" + user.getSenha() +
				"\", permissoes=" + user.getPermissoes() +
				", nome=\"" + user.getNome() +
				"\", email=\"" + user.getEmail() + 
				"\" WHERE binary login like\"" + user.getLogin() + "\"");
	}

	public void insereUsuario(Usuario user) throws UsuarioExcecao, SQLException{
		if (getUsuario(user.getLogin()) != null){
			throw new UsuarioExcecao("Usuario ja cadastrado");
		}
		this.execute("INSERT INTO Usuario " +
				"(login,senha,permissoes,nome,email) " +
				"VALUES (\"" + user.getLogin() + "\",\"" +
							 user.getSenha() + "\"," +
							 user.getPermissoes() + ",\"" +
							 user.getNome() + "\",\"" +
							 user.getEmail() + "\")");
	}

	public void deleteUsuario(Usuario user) throws SQLException{
		this.execute("DELETE from Usuario WHERE binary login like\"" + user.getLogin() + "\"");
	}
	
	public Usuario getUsuario(String login) throws SQLException{
		Usuario user = null;

		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Usuario WHERE binary login like\"" + login +"\"");
		
		if (resultado.next()){
			user = new Usuario(resultado.getInt("permissoes"), resultado.getString("login"), resultado.getString("senha"), resultado.getString("nome"), resultado.getString("email"));
		}
		
		resultado.close();
				
		return user;
	}
	
	public void setCurso(Curso curso) throws SQLException, UsuarioExcecao{

                if (!(getCurso(curso.getLogin()).getUnidade().equals(curso.getUnidade()))){
                    if (getListaDeAtletas(curso.getLogin(), "curso").size() > 0){
			throw new UsuarioExcecao("Erro ao alterar unidade academica: Ainda ha atletas neste curso");
                    }
                    if (getListaDeTimes(curso.getLogin(), "curso").size() > 0){
			throw new UsuarioExcecao("Erro ao alterar unidade academica: Ainda ha times neste curso");
                    }
                }

                this.setUsuario(curso);
		this.execute("UPDATE Curso SET" +
				" unidade=\"" + curso.getUnidade() +
				"\", id_listaDeTimes=\"" + curso.getListaDeTimes().toString() + 
				"\" WHERE binary login like\"" + curso.getLogin() + "\"");
	}

	public void insereCurso(Curso curso) throws UsuarioExcecao, SQLException {
		this.insereUsuario(curso);
		this.execute("INSERT INTO Curso " +
				"(login,unidade,id_listaDeTimes)" +
				"VALUES (\"" + curso.getLogin() + "\",\"" +
							 curso.getUnidade() + "\",\"" +
							 curso.getListaDeTimes().toString() + "\")");
	}

	public void deleteCurso(Curso curso) throws SQLException, UsuarioExcecao{
		if (getListaDeAtletas(curso.getLogin(), "curso").size() > 0){
			throw new UsuarioExcecao("Ainda ha atletas neste curso");
		}
		if (getListaDeTimes(curso.getLogin(), "curso").size() > 0){
			throw new UsuarioExcecao("Ainda ha times neste curso");
		}
		
		this.deleteUsuario(curso);
		this.execute("DELETE from Curso WHERE binary login like\"" + curso.getLogin() + "\"");
	}
	
	public Curso getCurso(String login) throws SQLException {
		Curso curso = null;
		
		Statement statement = conexao.createStatement();
		Statement statement2 = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Usuario WHERE binary login like\"" + login +"\"");
		ResultSet resultado2 = statement2.executeQuery("SELECT * FROM Curso WHERE binary login like\"" + login +"\"");
		
		if ((resultado.next()) && (resultado2.next())){
			curso = new Curso(resultado.getInt("permissoes"), resultado.getString("login"), resultado.getString("senha"), resultado.getString("nome"), resultado.getString("email"), resultado2.getString("unidade"));
			curso.setListaDeTimes(this.fromString(resultado2.getString("id_listaDeTimes")));
		}
		
		resultado.close();
		resultado2.close();
				
		return curso;
	}

	public void setModalidade(Modalidade modalidade) throws SQLException, ModalidadeExcecao{
		if (getListaDeTimes(((Integer) modalidade.getId()).toString(), "modalidade").size() > 0){
			throw new ModalidadeExcecao("Ainda ha times nesta modalidade");
		}
		
		this.execute("UPDATE Modalidade SET" +
				" nome=\"" + modalidade.getNome() +
				"\", quantMaxTimes=" + modalidade.getQuantMaxTimes() +
				", quantMinAtletas=" + modalidade.getQuantMinAtletas() +
				", quantMaxAtletas=" + modalidade.getQuantMaxAtletas() +
				", genero=" + modalidade.getGenero() +
				", tipo=" + modalidade.getTipo() + 
				" WHERE id=" + modalidade.getId());
	}

	public int insereModalidade(Modalidade modalidade) throws SQLException{
		return this.execute("INSERT INTO Modalidade " +
				"(nome,quantMaxTimes,quantMinAtletas,quantMaxAtletas,genero,tipo) " +
				"VALUES (\"" + modalidade.getNome() + "\"," +
							 modalidade.getQuantMaxTimes() + "," +
							 modalidade.getQuantMinAtletas() + "," +
							 modalidade.getQuantMaxAtletas() + "," +
							 modalidade.getGenero() + "," +
							 modalidade.getTipo() + ")");
	}

	public void deleteModalidade(Modalidade modalidade) throws SQLException, ModalidadeExcecao{
		if (getListaDeTimes(((Integer) modalidade.getId()).toString(), "modalidade").size() > 0){
			throw new ModalidadeExcecao("Ainda ha times nesta modalidade");
		}
		this.execute("DELETE from Modalidade WHERE id=" + modalidade.getId());
	}
	
	public Modalidade getModalidade(int idModalidade) throws SQLException{
		Modalidade modalidade = null;
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Modalidade WHERE id=" + idModalidade);
		
		if (resultado.next()){
			modalidade = new Modalidade(resultado.getString("nome"), resultado.getInt("quantMinAtletas"), resultado.getInt("quantMaxAtletas"), resultado.getInt("quantMaxTimes"), resultado.getInt("genero"), resultado.getInt("tipo"));
			modalidade.setId(idModalidade);
		}
		
		resultado.close();
				
		return modalidade;
	}
	
	public void setTime(Time time) throws SQLException{
		this.execute("UPDATE Time SET" +
				" modalidade=" + time.getIdModalidade() +
				", curso=\"" + time.getCurso() +
				"\", id_listaDeAtletas=\"" + time.getListaDeAtletas().toString() +
				"\" WHERE id=" + time.getId());
	}

	public int insereTime(Time time) throws SQLException{
		return this.execute("INSERT INTO Time " +
				"(modalidade,curso,id_listaDeAtletas)" +
				"VALUES (" + time.getIdModalidade() + ",\"" +
							 time.getCurso() + "\",\"" +
							 time.getListaDeAtletas().toString() + "\")");
	}

	public void deleteTime(Time time) throws SQLException{
		this.execute("DELETE from Time WHERE id=\"" + time.getId() + "\"");
	}
	
	public Time getTime(int idTime) throws SQLException{
		Time time = null;
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Time WHERE id=" + idTime);
		
		if (resultado.next()){
			time = new Time(resultado.getInt("modalidade"), resultado.getString("curso"));
			time.setListaDeAtletas(this.fromString(resultado.getString("id_listaDeAtletas")));
			time.setId(idTime);
		}
		
		resultado.close();
				
		return time;
	}
	
	public void setAtleta(Atleta atleta) throws SQLException{
		this.execute("UPDATE Atleta SET" +
				" matricula=\"" + atleta.getMatricula() +
				"\", nome=\"" + atleta.getNome() +
				"\", rg=\"" + atleta.getRg() +
				"\", genero=" + atleta.getGenero() +
				", curso=\"" + atleta.getCurso() +
				"\", id_listaDeTimes=\"" + atleta.getListaDeTimes().toString() +
				"\" WHERE id=" + atleta.getId());
	}

	public int insereAtleta(Atleta atleta) throws SQLException{
		return this.execute("INSERT INTO Atleta " +
				"(matricula,nome,rg,genero,curso,id_listaDeTimes)" +
				"VALUES (\"" + atleta.getMatricula() + "\",\"" +
							 atleta.getNome() + "\",\"" +
							 atleta.getRg() + "\"," +
							 atleta.getGenero() + ",\"" +
							 atleta.getCurso() + "\",\"" +
							 atleta.getListaDeTimes().toString() + "\")");
	}

	public void deleteAtleta(Atleta atleta) throws SQLException, AtletaExcecao{
		if (atleta.getListaDeTimes().size() > 0){
			throw new AtletaExcecao("Atleta ainda esta em algum time");
		}
		this.execute("DELETE from Atleta WHERE id=\"" + atleta.getId() + "\"");
	}
	
	public Atleta getAtleta(int idAtleta) throws SQLException {
		Atleta atleta = null;
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Atleta WHERE id=" + idAtleta);
		
		if (resultado.next()){
			atleta = new Atleta(resultado.getString("matricula"), resultado.getString("rg"), resultado.getString("nome"), resultado.getInt("genero"), resultado.getString("curso"));
			atleta.setListaDeTimes(this.fromString(resultado.getString("id_listaDeTimes")));
			atleta.setId(idAtleta);
		}
		
		resultado.close();	
				
		return atleta;
	}
	
	public ArrayList<String> getListaDeUsuarios(String string, String coluna) throws SQLException{
		ArrayList<String> listaDeUsuarios = new ArrayList<String>(0);
		
		String busca = "";
		if ((string != null) && (coluna != null)){
			if (coluna.equals("login")){
				busca = " WHERE login like \"%" + string + "%\"";
			} else{
				if (coluna.equals("nome")){
					busca = " WHERE nome like \"%" + string + "%\"";
				} else{
					if (coluna.equals("email")){
						busca = " WHERE email like \"%" + string + "%\"";
					}
				}
			}			
		}
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Usuario" + busca);
		
		while (resultado.next()){
			listaDeUsuarios.add(resultado.getString("login"));
		}
		
		resultado.close();
		
		return listaDeUsuarios;
	}
	
	public ArrayList<String> getListaDeCursos() throws SQLException {
		ArrayList<String> listaDeCursos = new ArrayList<String>(0);
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Curso");
		
		while (resultado.next()){
			listaDeCursos.add(resultado.getString("login"));
		}
		
		resultado.close();
		
		return listaDeCursos;
	}
	
	public ArrayList<Integer> getListaDeModalidades(String string, String coluna) throws SQLException {
		ArrayList<Integer> listaDeModalidades = new ArrayList<Integer>(0);

		String busca = "";
		if ((string != null) && (coluna != null)){
			if (coluna.equals("nome")){
				busca = " WHERE nome like \"%" + string + "%\"";
			}			
		}
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Modalidade" + busca);
		
		while (resultado.next()){
			listaDeModalidades.add(resultado.getInt("id"));
		}
		
		resultado.close();
		
		return listaDeModalidades;
	}
	
	public ArrayList<Integer> getListaDeAtletas(String string, String coluna, String curso) throws SQLException {
		ArrayList<Integer> listaDeAtletas = new ArrayList<Integer>(0);

		String busca = "";
		if ((string != null) && (coluna != null)){
			if (coluna.equals("nome")){
				busca = " WHERE nome like \"%" + string + "%\"";
			} else{
				if (coluna.equals("matricula")){
					busca = " WHERE matricula like \"%" + string + "%\"";
				} else{
					if (coluna.equals("rg")){
						busca = " WHERE rg like \"%" + string + "%\"";
					} else{
						if (coluna.equals("curso")){
							busca = " WHERE curso like \"%" + string + "%\"";
						}
					}
				}
			}			
		}

                if (curso != null){
                    busca = busca + " AND curso like \"%" + curso + "%\"";
                }
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Atleta" + busca);
		
		while (resultado.next()){
			listaDeAtletas.add(resultado.getInt("id"));
		}
		
		resultado.close();
		
		return listaDeAtletas;
	}

        public ArrayList<Integer> getListaDeAtletas(String string, String coluna) throws SQLException{
            return getListaDeAtletas(string, coluna, null);
        }
	
	public ArrayList<Integer> getListaDeTimes(String string, String coluna) throws SQLException {
		ArrayList<Integer> listaDeTimes = new ArrayList<Integer>(0);

		String busca = "";
		if ((string != null) && (coluna != null)){
			if (coluna.equals("modalidade")){
				busca = " WHERE modalidade like \"%" + string + "%\"";
			} else{
				if (coluna.equals("curso")){
					busca = " WHERE curso like \"%" + string + "%\"";
				}
			}			
		}
		
		
		Statement statement = conexao.createStatement();
		ResultSet resultado = statement.executeQuery("SELECT * FROM Time" + busca);
		
		while (resultado.next()){
			listaDeTimes.add(resultado.getInt("id"));
		}
		
		resultado.close();
		
		return listaDeTimes;
	}
}